package com.alinesno.infra.smart.assistant.scene.scene.documentReader.controller;

import cn.hutool.core.util.IdUtil;
import com.alinesno.infra.common.core.constants.SpringInstanceScope;
import com.alinesno.infra.common.extend.datasource.annotation.DataPermissionQuery;
import com.alinesno.infra.common.facade.datascope.PermissionQuery;
import com.alinesno.infra.common.facade.response.AjaxResult;
import com.alinesno.infra.common.facade.response.R;
import com.alinesno.infra.common.web.adapter.rest.SuperController;
import com.alinesno.infra.smart.assistant.adapter.SmartDocumentConsumer;
import com.alinesno.infra.smart.assistant.adapter.service.CloudStorageConsumer;
import com.alinesno.infra.smart.assistant.scene.scene.documentReader.dto.DocReaderSceneInfoDto;
import com.alinesno.infra.smart.assistant.scene.scene.documentReader.service.IDocReaderSceneService;
import com.alinesno.infra.smart.assistant.scene.scene.documentReader.service.IDocReaderTaskService;
import com.alinesno.infra.smart.assistant.scene.scene.documentReview.tools.AnalysisTool;
import com.alinesno.infra.smart.assistant.scene.scene.longtext.dto.LongTextSceneDto;
import com.alinesno.infra.smart.assistant.service.IIndustryRoleService;
import com.alinesno.infra.smart.scene.dto.SceneInfoDto;
import com.alinesno.infra.smart.scene.entity.DocReaderSceneEntity;
import com.alinesno.infra.smart.scene.entity.DocReaderTaskEntity;
import com.alinesno.infra.smart.scene.entity.SceneEntity;
import com.alinesno.infra.smart.scene.enums.SceneEnum;
import com.alinesno.infra.smart.scene.service.ISceneService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.lang.exception.RpcServiceRuntimeException;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Objects;

/**
 * 处理与BusinessLogEntity相关的请求的Controller。
 * 继承自BaseController类并实现IBusinessLogService接口。
 *
 * @author luoxiaodong
 * @version 1.0.0
 */
@Slf4j
@RestController
@Scope(SpringInstanceScope.PROTOTYPE)
@RequestMapping("/api/infra/smart/assistant/scene/documentReader")
public class DocReaderController extends SuperController {

    @Autowired
    private IDocReaderSceneService docReaderSceneService; ;

    @Autowired
    private ISceneService service;

    @Autowired
    private IDocReaderTaskService docReaderTaskService ;

    @Autowired
    private IIndustryRoleService industryRoleService;

    @Autowired
    private CloudStorageConsumer storageConsumer ;

    @Autowired
    private SmartDocumentConsumer smartDocumentConsumer ;

    @Autowired
    private AnalysisTool analysisTool;

    @Value("${alinesno.file.local.path:${java.io.tmpdir}}")
    private String localPath  ;

    /**
     * 通过Id获取到场景
     *
     * @return
     */
    @GetMapping("/getScene")
    public AjaxResult getScene(@RequestParam("id") long id) {

        Assert.isTrue(id > 0, "参数不能为空");

        SceneEntity entity = service.getById(id);
        if (entity == null) {
            return AjaxResult.error("未找到对应的场景实体");
        }

        LongTextSceneDto dto = new LongTextSceneDto();
        BeanUtils.copyProperties(entity, dto);

        SceneInfoDto sceneInfoDto = SceneEnum.getSceneInfoByCode(entity.getSceneType());

        dto.setAgents(sceneInfoDto.getAgents());
        dto.setSceneId(sceneInfoDto.getId());

        DocReaderSceneInfoDto docSceneInfoDto = new DocReaderSceneInfoDto();
        BeanUtils.copyProperties(dto, docSceneInfoDto);

        // 查询出Entity信息
        LambdaQueryWrapper<DocReaderSceneEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DocReaderSceneEntity::getSceneId, id);
        DocReaderSceneEntity docReviewSceneEntity = docReaderSceneService.getOne(wrapper);

        if(docReviewSceneEntity != null){
            docSceneInfoDto.setSummaryAgentEngineer(docReviewSceneEntity.getSummaryAgentEngineer());
            docSceneInfoDto.setSummaryAgentEngineerEntity(industryRoleService.getById(docReviewSceneEntity.getSummaryAgentEngineer()));

            docSceneInfoDto.setReaderQueryAgentEngineer(docReviewSceneEntity.getReaderQueryAgentEngineer());
            docSceneInfoDto.setReaderQueryAgentEngineerEntity(industryRoleService.getById(docReviewSceneEntity.getReaderQueryAgentEngineer()));

            docSceneInfoDto.setDocumentId(docReviewSceneEntity.getDocumentId());
            docSceneInfoDto.setDocumentName(docReviewSceneEntity.getDocumentName());

        }

        return AjaxResult.success("操作成功.", docSceneInfoDto);
    }

    /**
     * 返回预览文档的二进制（尽量返回 PDF bytes 以供 pdf.js 渲染，如果是其他类型则按原始类型返回）
     */
    @SneakyThrows
    @DataPermissionQuery
    @GetMapping("/getPreviewDocxUrl")
    public  AjaxResult getPreviewDocxUrl(@RequestParam long taskId, PermissionQuery query) {

        DocReaderTaskEntity entity = docReaderTaskService.getById(taskId);

        String previewUrl = storageConsumer.getPreviewUrl(entity.getDocumentId()).getData();
        log.debug("previewUrl= {}", previewUrl);

        return AjaxResult.success("获取预览成功" , previewUrl) ;
    }

    /**
     * 返回预览文档的二进制（尽量返回 PDF bytes 以供 pdf.js 渲染，如果是其他类型则按原始类型返回）
     */
    @SneakyThrows
    @DataPermissionQuery
    @GetMapping("/getPreviewDocx")
    public ResponseEntity<Resource> getPreviewDocx(@RequestParam long taskId, PermissionQuery query) {

//        DocReaderSceneEntity entity = docReaderSceneService.getBySceneId(sceneId, query);
        DocReaderTaskEntity entity = docReaderTaskService.getById(taskId);
        if (entity == null) {
            return ResponseEntity.notFound().build();
        }

        String previewUrl = storageConsumer.getPreviewUrl(entity.getDocumentId()).getData();
        log.debug("previewUrl= {}", previewUrl);
        if (previewUrl == null || previewUrl.trim().isEmpty()) {
            return ResponseEntity.notFound().build();
        }

        byte[] fileBytes;
        String detectedContentType = null;
        String filename = "preview";

        try (InputStream inputStream = new URL(previewUrl).openStream()) {
            // 尝试通过 URL 头部获取 content-type
            URLConnection conn = new URL(previewUrl).openConnection();
            detectedContentType = conn.getContentType();

            // 若 URL 中包含文件名，尝试解析
            String path = conn.getURL().getPath();
            if (path != null && path.contains("/")) {
                String tmp = path.substring(path.lastIndexOf('/') + 1);
                if (tmp != null && tmp.length() > 0) {
                    filename = tmp;
                }
            }

            // 读取字节
            fileBytes = IOUtils.toByteArray(inputStream);
        } catch (Exception ex) {
            log.error("读取 previewUrl 失败: {}", previewUrl, ex);
            return ResponseEntity.badRequest().build();
        }

        if (fileBytes == null || fileBytes.length == 0) {
            return ResponseEntity.noContent().build();
        }

        // 如果无法检测 content-type，尝试根据文件名后缀推断
        if (detectedContentType == null || detectedContentType.trim().isEmpty()) {
            String lower = filename.toLowerCase();
            if (lower.endsWith(".pdf")) {
                detectedContentType = "application/pdf";
            } else if (lower.endsWith(".docx")) {
                detectedContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            } else if (lower.endsWith(".doc")) {
                detectedContentType = "application/msword";
            } else {
                detectedContentType = "application/octet-stream";
            }
        }

        log.debug("detectedContentType = {}", detectedContentType);

        HttpHeaders headers = new HttpHeaders();
        MediaType mediaType;
        try {
            mediaType = MediaType.parseMediaType(detectedContentType);
        } catch (Exception ex) {
            mediaType = MediaType.APPLICATION_OCTET_STREAM;
        }
        headers.setContentType(mediaType);

        // inline 以便前端直接展示
        String safeFileName = filename.replaceAll("[\\s\\\\/:*?\"<>|]+", "_");
        headers.add("Content-Disposition", "inline; filename=\"" + safeFileName + "\"");
        headers.add("Content-Length", String.valueOf(fileBytes.length));

        ByteArrayResource resource = new ByteArrayResource(fileBytes);
        return ResponseEntity.ok()
                .headers(headers)
                .body(resource);
    }

    /**
     * 文件上传
     * @return
     */
    @SneakyThrows
    @DataPermissionQuery
    @PostMapping("/importData")
    public AjaxResult importData(@RequestPart("file") MultipartFile file, long sceneId , PermissionQuery query){

        log.debug("sceneId = {}" , sceneId);

        // 新生成的文件名称
        String fileName = file.getOriginalFilename() ;
        String fileSuffix = Objects.requireNonNull(fileName).substring(fileName.lastIndexOf(".")+1);
        String newFileName = IdUtil.getSnowflakeNextId() + "." + fileSuffix;

        // 判断文件名是否存在，存在则提示文件名已存在
        if (docReaderTaskService.count(new LambdaQueryWrapper<DocReaderTaskEntity>()
                .eq(DocReaderTaskEntity::getSceneId, sceneId)
                .eq(DocReaderTaskEntity::getTaskName, fileName)) > 0) {

            throw new RpcServiceRuntimeException("文件名"+fileName+"已存在");
        }

        // 复制文件
        File targetFile = new File(localPath , newFileName);
        FileUtils.writeByteArrayToFile(targetFile, file.getBytes());

        log.debug("newFileName = {} , targetFile = {}" , newFileName , targetFile.getAbsoluteFile());

        // TODO 如果是非PDF文件，则转换成PDF
        File fileToUpload = targetFile;
        String uploadSuffix = fileSuffix;

        if (!"pdf".equalsIgnoreCase(fileSuffix)) {
            try {
                // 调用远程服务将非 PDF 转为 PDF（返回 PDF bytes）
                byte[] pdfBytes = smartDocumentConsumer.convertToPdf(targetFile);
                if (pdfBytes != null && pdfBytes.length > 0) {
                    // 生成临时 pdf 文件并写入字节
                    String pdfFileName = IdUtil.getSnowflakeNextId() + ".pdf";
                    File pdfFile = new File(localPath, pdfFileName);
                    FileUtils.writeByteArrayToFile(pdfFile, pdfBytes);

                    // 将要上传的文件替换为生成的 pdf 文件
                    fileToUpload = pdfFile;
                    uploadSuffix = "pdf";

                    log.debug("已将文件转换为 PDF: {}", pdfFile.getAbsolutePath());
                } else {
                    log.warn("convertToPdf 返回空，使用原始文件上传: {}", targetFile.getAbsolutePath());
                }
            } catch (Exception e) {
                log.error("将文件转换为 PDF 失败，使用原始文件上传: {}", targetFile.getAbsolutePath(), e);
                // 出错时回退为原文件上传
                fileToUpload = targetFile;
                uploadSuffix = fileSuffix;
            }
        }

        R<String> r = storageConsumer.upload(fileToUpload);

        // 上传完成后尝试删除临时文件（如果生成了 PDF 则删除之，保留原始上传文件根据需求也可以删除）
        try {
            if (!fileToUpload.equals(targetFile)) {
                if (!fileToUpload.delete()) {
                    fileToUpload.deleteOnExit();
                }
            }
            // 可选：删除原始临时文件
            if (targetFile.exists()) {
                if (!targetFile.delete()) {
                    targetFile.deleteOnExit();
                }
            }
        } catch (Exception ex) {
            log.warn("删除临时文件时发生异常", ex);
        }

        // 添加任务
        DocReaderTaskEntity taskEntity = docReaderTaskService.addTask(fileName , r.getData() , fileSuffix , sceneId ,   query) ;

        log.debug("ajaxResult= {}" , r);
        AjaxResult ok = AjaxResult.success("上传成功." , r.getData()) ;
        ok.put("taskId" , taskEntity.getId()) ;
        ok.put("channelStreamId" , taskEntity.getChannelStreamId());

        return ok ;
    }

}